package com.yhh.college_information_platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yhh.college_information_platform.common.PageResult;
import com.yhh.college_information_platform.common.ResultCode;
import com.yhh.college_information_platform.constant.CommonConstant;
import com.yhh.college_information_platform.dto.*;
import com.yhh.college_information_platform.entity.User;
import com.yhh.college_information_platform.exception.BusinessException;
import com.yhh.college_information_platform.mapper.UserMapper;
import com.yhh.college_information_platform.service.UserService;
import com.yhh.college_information_platform.utils.JwtUtil;
import com.yhh.college_information_platform.utils.MinioUtil;
import com.yhh.college_information_platform.vo.LoginVO;
import com.yhh.college_information_platform.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户Service实现类
 *
 * @author yhh
 * @date 2025-10-05
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private MinioUtil minioUtil;

    @Value("${file.avatar.allowed-types:jpg,jpeg,png,gif}")
    private String allowedAvatarTypes;

    @Value("${file.avatar.max-size:5242880}")
    private Long maxAvatarSize;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserRegisterDTO registerDTO) {
        // 1. 校验两次密码是否一致
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "两次输入的密码不一致");
        }

        // 2. 检查学号是否已存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getStudentId, registerDTO.getStudentId());
        User existUser = userMapper.selectOne(wrapper);
        if (existUser != null) {
            throw new BusinessException(ResultCode.USER_EXIST);
        }

        // 3. 创建用户对象
        User user = new User();
        user.setStudentId(registerDTO.getStudentId());
        user.setNickname(registerDTO.getNickname());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        user.setRole(CommonConstant.ROLE_USER);
        user.setStatus(CommonConstant.USER_STATUS_ENABLED);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());

        // 4. 保存用户
        int result = userMapper.insert(user);
        if (result <= 0) {
            throw new BusinessException(ResultCode.DATABASE_ERROR);
        }

        log.info("用户注册成功：{}", registerDTO.getStudentId());
    }

    @Override
    public LoginVO login(UserLoginDTO loginDTO) {
        // 1. 根据学号查询用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getStudentId, loginDTO.getStudentId());
        User user = userMapper.selectOne(wrapper);

        // 2. 检查用户是否存在
        if (user == null) {
            throw new BusinessException(ResultCode.LOGIN_ERROR);
        }

        // 3. 检查用户状态
        if (CommonConstant.USER_STATUS_DISABLED.equals(user.getStatus())) {
            throw new BusinessException(ResultCode.USER_DISABLED);
        }

        // 4. 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new BusinessException(ResultCode.LOGIN_ERROR);
        }

        // 5. 更新最后登录时间
        user.setLastLoginTime(LocalDateTime.now());
        userMapper.updateById(user);

        // 6. 生成Token
        String token = jwtUtil.generateToken(user.getId(), user.getStudentId(), user.getRole());

        // 7. 构建返回对象
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        LoginVO loginVO = new LoginVO(token, userVO);

        log.info("用户登录成功：{}", loginDTO.getStudentId());
        return loginVO;
    }

    @Override
    public UserVO getUserInfo(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        return BeanUtil.copyProperties(user, UserVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserInfo(Long userId, UserUpdateDTO updateDTO) {
        // 1. 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 2. 更新用户信息
        User updateUser = new User();
        updateUser.setId(userId);
        
        if (StrUtil.isNotBlank(updateDTO.getNickname())) {
            updateUser.setNickname(updateDTO.getNickname());
        }
        
        if (StrUtil.isNotBlank(updateDTO.getEmail())) {
            // 检查邮箱是否已被使用
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getEmail, updateDTO.getEmail())
                   .ne(User::getId, userId);
            if (userMapper.selectCount(wrapper) > 0) {
                throw new BusinessException(ResultCode.EMAIL_EXIST);
            }
            updateUser.setEmail(updateDTO.getEmail());
        }

        int result = userMapper.updateById(updateUser);
        if (result <= 0) {
            throw new BusinessException(ResultCode.DATABASE_ERROR);
        }

        log.info("用户信息更新成功，用户ID：{}", userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(Long userId, PasswordUpdateDTO passwordDTO) {
        // 1. 校验两次密码是否一致
        if (!passwordDTO.getNewPassword().equals(passwordDTO.getConfirmPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "两次输入的新密码不一致");
        }

        // 2. 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 3. 验证旧密码
        if (!passwordEncoder.matches(passwordDTO.getOldPassword(), user.getPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "旧密码错误");
        }

        // 4. 检查新密码是否与旧密码相同
        if (passwordDTO.getOldPassword().equals(passwordDTO.getNewPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "新密码不能与旧密码相同");
        }

        // 5. 更新密码
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setPassword(passwordEncoder.encode(passwordDTO.getNewPassword()));
        updateUser.setUpdateTime(LocalDateTime.now());

        int result = userMapper.updateById(updateUser);
        if (result <= 0) {
            throw new BusinessException(ResultCode.DATABASE_ERROR);
        }

        log.info("用户密码修改成功，用户ID：{}", userId);
    }

    @Override
    public UserVO getUserByStudentId(String studentId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getStudentId, studentId);
        User user = userMapper.selectOne(wrapper);

        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        return BeanUtil.copyProperties(user, UserVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadAvatar(Long userId, MultipartFile file) {
        // 验证用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 验证文件
        validateAvatarFile(file);

        try {
            // 上传头像到 MinIO
            String avatarUrl = minioUtil.uploadFile(file);

            // 更新用户头像URL
            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setAvatar(avatarUrl);
            updateUser.setUpdateTime(LocalDateTime.now());

            int result = userMapper.updateById(updateUser);
            if (result <= 0) {
                throw new BusinessException(ResultCode.SYSTEM_ERROR, "头像更新失败");
            }

            log.info("用户{}头像上传成功，URL: {}", userId, avatarUrl);
            return avatarUrl;
        } catch (Exception e) {
            log.error("头像上传失败", e);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "头像上传失败: " + e.getMessage());
        }
    }

    /**
     * 验证头像文件
     */
    private void validateAvatarFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "头像文件不能为空");
        }

        // 验证文件大小
        if (file.getSize() > maxAvatarSize) {
            throw new BusinessException(ResultCode.FILE_SIZE_ERROR, 
                    "头像文件大小不能超过 " + (maxAvatarSize / 1024 / 1024) + "MB");
        }

        // 验证文件类型
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "文件名不能为空");
        }

        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        List<String> allowedTypes = Arrays.asList(allowedAvatarTypes.split(","));

        if (!allowedTypes.contains(fileExtension)) {
            throw new BusinessException(ResultCode.FILE_TYPE_ERROR, 
                    "仅支持以下格式的头像：" + allowedAvatarTypes);
        }
    }

    @Override
    public PageResult<UserVO> getUserPage(UserQueryDTO queryDTO) {
        // 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        
        // 关键词搜索（学号、昵称、邮箱）
        if (StrUtil.isNotBlank(queryDTO.getKeyword())) {
            wrapper.and(w -> w
                .like(User::getStudentId, queryDTO.getKeyword())
                .or()
                .like(User::getNickname, queryDTO.getKeyword())
                .or()
                .like(User::getEmail, queryDTO.getKeyword())
            );
        }
        
        // 角色筛选
        if (StrUtil.isNotBlank(queryDTO.getRole())) {
            wrapper.eq(User::getRole, queryDTO.getRole());
        }
        
        // 状态筛选
        if (queryDTO.getStatus() != null) {
            wrapper.eq(User::getStatus, queryDTO.getStatus());
        }
        
        // 按创建时间倒序
        wrapper.orderByDesc(User::getCreateTime);
        
        // 分页查询
        Page<User> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        page = userMapper.selectPage(page, wrapper);
        
        // 转换为VO
        List<UserVO> userVOList = page.getRecords().stream()
            .map(this::convertToVO)
            .collect(Collectors.toList());
        
        PageResult<UserVO> result = new PageResult<>();
        result.setRecords(userVOList);
        result.setTotal(page.getTotal());
        result.setCurrent(page.getCurrent());
        result.setSize(page.getSize());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserByAdmin(Long userId, UserUpdateDTO updateDTO, Long adminId) {
        // 1. 验证用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        
        // 2. 不能修改自己的角色和状态
        if (userId.equals(adminId)) {
            if (updateDTO.getRole() != null || updateDTO.getStatus() != null) {
                throw new BusinessException(ResultCode.OPERATION_ERROR, "不能修改自己的角色或状态");
            }
        }
        
        // 3. 更新用户信息
        User updateUser = new User();
        updateUser.setId(userId);
        
        if (StrUtil.isNotBlank(updateDTO.getNickname())) {
            updateUser.setNickname(updateDTO.getNickname());
        }
        
        if (StrUtil.isNotBlank(updateDTO.getEmail())) {
            // 检查邮箱是否已被使用
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getEmail, updateDTO.getEmail())
                   .ne(User::getId, userId);
            if (userMapper.selectCount(wrapper) > 0) {
                throw new BusinessException(ResultCode.EMAIL_EXIST);
            }
            updateUser.setEmail(updateDTO.getEmail());
        }
        
        if (StrUtil.isNotBlank(updateDTO.getRole())) {
            updateUser.setRole(updateDTO.getRole());
        }
        
        if (updateDTO.getStatus() != null) {
            updateUser.setStatus(updateDTO.getStatus());
        }
        
        int rows = userMapper.updateById(updateUser);
        if (rows <= 0) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "更新用户信息失败");
        }
        
        log.info("管理员{}更新用户{}信息成功", adminId, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByAdmin(Long userId, Long adminId) {
        // 1. 验证用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        
        // 2. 不能删除自己
        if (userId.equals(adminId)) {
            throw new BusinessException(ResultCode.OPERATION_ERROR, "不能删除自己的账号");
        }
        
        // 3. 不能删除管理员账号（保护措施）
        if ("admin".equals(user.getRole())) {
            throw new BusinessException(ResultCode.OPERATION_ERROR, "不能删除管理员账号");
        }
        
        // 4. 删除用户
        int rows = userMapper.deleteById(userId);
        if (rows <= 0) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "删除用户失败");
        }
        
        log.info("管理员{}删除用户{}成功", adminId, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String resetPassword(Long userId, Long adminId) {
        // 1. 验证用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        
        // 2. 生成新密码（默认：123456）
        String newPassword = "123456";
        String encodedPassword = passwordEncoder.encode(newPassword);
        
        // 3. 更新密码
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setPassword(encodedPassword);
        
        int rows = userMapper.updateById(updateUser);
        if (rows <= 0) {
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "重置密码失败");
        }
        
        log.info("管理员{}重置用户{}密码成功", adminId, userId);
        return newPassword;
    }

    /**
     * 转换为UserVO
     */
    private UserVO convertToVO(User user) {
        UserVO vo = new UserVO();
        BeanUtil.copyProperties(user, vo);
        return vo;
    }
}
